package com.zoe.onelink.core.web.validation.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.zoe.onelink.common.enumeration.ExceptionCodeEnum;
import com.zoe.onelink.common.exception.ApiException;
import com.zoe.onelink.core.util.ParameterHelper;
import com.zoe.onelink.core.web.validation.annotation.Required;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/**
 * <p>标题: 入参验证切面</p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2016</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: cxy, ffs
 * @date 2016/11/1
 */
@Aspect
public class ParameterAspect {

    @Pointcut("within(@org.springframework.stereotype.Controller * || @org.springframework.web.bind.annotation.RestController *)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        // 获取该方法参数
        Parameter[] parameters = ms.getMethod().getParameters();
        // 获取该方法参数值
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (parameter.isAnnotationPresent(Required.class)) {
                Required required = parameter.getAnnotation(Required.class);
                Object arg = args[i];
                String[] paramNames = required.value();
                if (arg == null) {
                    throw ApiException.createEx(ExceptionCodeEnum.KEY_NOT_NULL, paramNames[0]);
                }
                Class<?> paramType = arg.getClass();
                if (ClassUtils.isPrimitiveOrWrapper(paramType) || arg instanceof String
                        || arg instanceof Date || arg instanceof BigDecimal) {
                    // 参数是基本类型及其包装类或者String类型或者Date类型
                    if (ObjectUtil.isEmpty(arg)) {
                        throw ApiException.createEx(ExceptionCodeEnum.VALUE_NOT_NULL, paramNames[0]);
                    }
                } else if (arg instanceof Map) {
                    // 参数是Map
                    Map<String, Object> map = (Map<String, Object>) arg;
                    ParameterHelper.checkKeys(map, paramNames);
                } else {
                    // 参数是JavaBean
                    ParameterHelper.checkFields(arg, paramNames);
                }
            }
        }
    }
}
